/**
 * 
 */
package com.glodon.paas.job.monitor.service;

import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.glodon.paas.exception.PaasServerExceptionFactory;
import com.glodon.paas.job.JobConstants;
import com.glodon.paas.job.exception.JsonException;
import com.glodon.paas.job.model.AlarmConfig;
import com.glodon.paas.job.model.AlarmInfo;
import com.glodon.paas.job.model.MonitorEvent;
import com.glodon.paas.job.model.MonitorEventType;
import com.glodon.paas.job.model.MonitorStatus;
import com.glodon.paas.job.util.JsonUtil;
import com.glodon.paas.mail.MailClientHttpImpl;
import com.glodon.paas.mail.MailMessageParam;
import com.glodon.paas.util.DateUtil;

/**
 * @author xur@grandsoft.com.cn
 *
 */

public class AlarmSchedule {
	
	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private AlarmService alarmService;
	@Autowired
	private MonitorStatusService monitorService;
	@Autowired
	private MailClientHttpImpl mailClient;
	
	@Autowired
	private MonitorStatusService monitorStatusService;
	
    @Autowired
    private RestTemplate template = new RestTemplate();
    
	public void process(){
		//Get alarm configuration
		AlarmConfig config = alarmService.getConfig();
		if(config!=null){
			if(config.isFaliureTrigger()){
				if(config.getAgentThreshold()>0){
					List<MonitorStatus> agentList= monitorService.getUnavalibalAgent(config.getAgentThreshold());
					for(MonitorStatus monitorStatus:agentList){
						String message=String.format(MailMessage.getString("agentUnavalibal"),monitorStatus.getTraceId(),config.getAgentThreshold()); //$NON-NLS-1$
						String title=MailMessage.getString("mail.title"); 
						String template = MailMessage.getString("mail.template");
						boolean result=sendMail(config.getSendTo(),message,title,template);
						//Insert alarm history
						saveAlarmInfo(message,result,title,template,config.getSendTo());
					}
				}
				checkServiceHealth(config);
			}
			if(config.getUnProcessThreshold()>0){
				int number = monitorService.getWaitingTaskNumber();
				if(number>config.getUnProcessThreshold()){
					String message=String.format(MailMessage.getString("waitingTask"),config.getUnProcessThreshold(),number);
					String title=MailMessage.getString("mail.title"); 
					String template = MailMessage.getString("mail.template");
					boolean result=sendMail(config.getSendTo(),message,title,template);
					//Insert alarm history
					saveAlarmInfo(message,result,title,template,config.getSendTo());
				}
			}
			if(config.getWaitingTimeThreshold()>0){
				int number = monitorService.getAvgWaitingTime();
				if(number>config.getWaitingTimeThreshold()){
					String message=String.format(MailMessage.getString("avgWaitingTime"),config.getWaitingTimeThreshold(),number);
					String title=MailMessage.getString("mail.title"); 
					String template = MailMessage.getString("mail.template");
					boolean result=sendMail(config.getSendTo(),message,title,template);
					//Insert alarm history
					saveAlarmInfo(message,result,title,template,config.getSendTo());
				}
			}
			if(config.getFailureRateTheshold()>0){
				 Calendar cal = Calendar.getInstance();
			        cal.add(Calendar.DAY_OF_YEAR, -7);
			        Date lastWeek = cal.getTime();
				List<MonitorStatus> monitorStatusList = monitorService.getMonitorStatus(MonitorEventType.AGENT_STATUS,
		                lastWeek);
				for(MonitorStatus status: monitorStatusList){
					Map jsonMap = new HashMap();
					try {
						jsonMap=JsonUtil.jsonToMap(status.getJson());
					} catch (JsonException e) {
						e.printStackTrace();
					}
					double fail =jsonMap.get("failure")==null?0:Integer.parseInt(jsonMap.get("failure").toString());
					double success =jsonMap.get("success")==null?0:Integer.parseInt(jsonMap.get("success").toString());
					if(fail!=0&&success!=0){
						double rate = fail/(fail+success);
						if(rate*100>config.getFailureRateTheshold()){
							NumberFormat nf   =   NumberFormat.getPercentInstance();     
							nf.setMinimumFractionDigits(2);
							String message=String.format(MailMessage.getString("failureRate"),status.getTraceId(),config.getFailureRateTheshold(),nf.format(rate));
							String title=MailMessage.getString("mail.title"); 
							String template = MailMessage.getString("mail.template");
							boolean result=sendMail(config.getSendTo(),message,title,template);
							//Insert alarm history
							saveAlarmInfo(message,result,title,template,config.getSendTo());
						}
					}
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public boolean checkServiceHealth(AlarmConfig config){
		boolean flag=true;
		int serviceThreshold=config.getServiceThreshold();
		String healthUrls=config.getHealthUrl();
		String[] url = healthUrls.split(",");
		if(url.length==0){
			return false;
		}
		for(String health: url){
			String[] healthUrlArray=health.split("[?]");
			String healthUrl=healthUrlArray[0];
			List<MonitorStatus> monitorStatusList=monitorStatusService.getByTypeAndTraceId(MonitorEventType.SERVER_STATUS, healthUrl);
			if(null!=monitorStatusList && !monitorStatusList.isEmpty()){
				MonitorStatus monitorStatus=(MonitorStatus)monitorStatusList.get(0);
				Date updatedTime=monitorStatus.getUpdatedTime();
				Date now=new Date();
				Integer daysInterval=DateUtil.minBetweenDate(updatedTime, now);
				if(null!=daysInterval && daysInterval.intValue()>serviceThreshold){
					flag=false;
					sendEmailSaveAlarmInfo(config, healthUrl,",the server has down.");
				}
			}
			Map map;
	        try {
	            logger.info("checkServiceHealth: {}", healthUrl);
	            map = template.getForObject(healthUrl, Map.class);
	        } catch (RestClientException e) {
	        	flag=false;
	        	sendEmailSaveAlarmInfo(config, healthUrl,e.getMessage());
	        	continue;
	        }
	        logger.info("healthUrl, response:{}", map);
	        if(null==map || map.isEmpty()){
	        	flag=false;
	        	sendEmailSaveAlarmInfo(config, healthUrl,",the reslut is empty.");
	        	continue;
	        }
	        String statusCode=(String)map.get("statusCode");
	        if(StringUtils.isEmpty(statusCode) || !StringUtils.equals(statusCode, "200")){
	        	flag=false;
	        	sendEmailSaveAlarmInfo(config, healthUrl,",the statusCode is empty or statusCode!=200.");
	        	continue;
	        }
	        String currentTime=(String)map.get("currentTime");
	        MonitorEvent monitorEvent =new MonitorEvent();
	        monitorEvent.setTraceId(healthUrl);
	        monitorEvent.setType(MonitorEventType.SERVER_STATUS);
	        monitorEvent.setTime(DateUtil.getDate(currentTime, "yyyy-MM-dd HH:mm:ss"));
	        monitorEvent.setValues(map);
	        monitorStatusService.processMonitorEvent(monitorEvent);
		}
		return flag;
	}

	private void sendEmailSaveAlarmInfo(AlarmConfig config, String healthUrl,String detailMessage) {
		String message=String.format(MailMessage.getString("healthServerUnavalibal"),healthUrl,config.getServiceThreshold())+detailMessage;
		String title=MailMessage.getString("mail.title"); 
		String template = MailMessage.getString("mail.template");
		boolean result=sendMail(config.getSendTo(),message,title,template);
		saveAlarmInfo(message,result,title,template,config.getSendTo());
	}
	
	private void saveAlarmInfo(String message,boolean isNotified,String title,String templateName,String sendTo){
		List<AlarmInfo> alarmInfoList=alarmService.getAlarmInfoNumMinutes(message);
		if(null!=alarmInfoList && !alarmInfoList.isEmpty()){
			return ;
		}
		AlarmInfo info = new AlarmInfo();
		Date date = new Date();
		info.setAlarmDetail(message);
		info.setCreateTime(date);
		info.setNotified(isNotified);
		info.setUpdateTime(date);
		info.setTitle(title);
		info.setTemplateName(templateName);
		info.setSendTo(sendTo);
		alarmService.saveAlarmInfo(info);
	}
	private boolean sendMail(String sendTo,String message,String title,String template){
		 Map<String, Object> param = new HashMap<String, Object>();     
	       param.put("messageBody", message); 
	       MailMessageParam mailContent = new MailMessageParam();
	       mailContent.setTo(sendTo.split(";"));
	       mailContent.setSubject(title);  
	       mailContent.setTemplateLocation(template);
	       mailContent.setTemplateParam(param);
		   int result = mailClient.sendMail(mailContent, false);
		   return result==200;
	}
	public void reNotify(){
		List<AlarmInfo> list = alarmService.getUnNotifiedAlarmInfo();
		for(AlarmInfo info : list){
			boolean result=sendMail(info.getSendTo(),info.getAlarmDetail(),info.getTitle(),info.getTemplateName());
			if(info.isNotified()!=result){
				info.setNotified(result);
				
			}
			info.setUpdateTime(new Date());
			alarmService.saveAlarmInfo(info);
		}
		
	}
	public AlarmService getAlarmService() {
		return alarmService;
	}
	public void setAlarmService(AlarmService alarmService) {
		this.alarmService = alarmService;
	}
	public MonitorStatusService getMonitorService() {
		return monitorService;
	}
	public void setMonitorService(MonitorStatusService monitorService) {
		this.monitorService = monitorService;
	}
	public MailClientHttpImpl getMailClient() {
		return mailClient;
	}
	public void setMailClient(MailClientHttpImpl mailClient) {
		this.mailClient = mailClient;
	}

	public MonitorStatusService getMonitorStatusService() {
		return monitorStatusService;
	}

	public void setMonitorStatusService(MonitorStatusService monitorStatusService) {
		this.monitorStatusService = monitorStatusService;
	}

	public RestTemplate getTemplate() {
		return template;
	}

	public void setTemplate(RestTemplate template) {
		this.template = template;
	}
	
	
}
